/**
 *
 */
package info.touret.winecellar.bottle.client;

import static info.touret.winecellar.dao.client.Constants.PAGE_SIZE;
import info.touret.winecellar.bottle.shared.BottleProxy;
import info.touret.winecellar.producer.client.ProducerRequestFactory;
import info.touret.winecellar.producer.shared.ProducerProxy;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import javax.inject.Inject;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.ClickableTextCell;
import com.google.gwt.cell.client.DatePickerCell;
import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.SelectionCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionModel;
import com.google.web.bindery.requestfactory.shared.EntityProxyChange;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.ServerFailure;
import com.google.web.bindery.requestfactory.shared.Violation;

/**
 * Widget qui gere la liste des bouteilles ( affichage /suppression /note )
 * 
 * @author touret-a
 */
public class BottleListUI extends Composite implements
		EntityProxyChange.Handler<BottleProxy>, Activity {

	@UiField(provided = true)
	SimplePager pager = new SimplePager(TextLocation.CENTER);

	@Inject
	Logger trace;

	interface BottleListUIUiBinder extends UiBinder<Widget, BottleListUI> {
	}

	private static BottleListUIUiBinder uiBinder = GWT
			.create(BottleListUIUiBinder.class);

	/**
	 * Constructeur par defaut
	 */
	public BottleListUI() {
		initWidget(uiBinder.createAndBindUi(this));
	}

	/**
	 * A utiliser par defaut charge les differentes donnees
	 * 
	 * @param factory
	 * @param producerrequestfactory
	 */
	public BottleListUI(BottleRequestFactory factory,
			ProducerRequestFactory producerrequestfactory) {
		this();
		bottlerequestFactory = factory;
		this.producerrequestFactory = producerrequestfactory;
		// Can access @UiField after calling createAndBindUi

		createTable();
		populateTable();
	}

	@UiField
	CellTable<BottleProxy> cellTable;

	private BottleRequestFactory bottlerequestFactory;
	private ProducerRequestFactory producerrequestFactory;

	@Override
	public String mayStop() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCancel() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onStop() {
		// TODO Auto-generated method stub

	}

	@Override
	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onProxyChange(EntityProxyChange<BottleProxy> event) {

	}

	private Receiver<List<BottleProxy>> lastDataBottleReceiver;

	private List<BottleProxy> lastBottlesData;

	private Request<List<BottleProxy>> getBottles(String criteria) {
		Request<List<BottleProxy>> producers = null;
		if (criteria == null || criteria.length() == 0) {
			producers = bottlerequestFactory.bottleRequest().findAllBottles();
		} else {
			producers = bottlerequestFactory.bottleRequest()
					.findBottlesByCriteria(criteria);
		}
		return producers;
	}

	/**
	 * Peuple la table des bouteilles
	 */
	private void populateTable() {
		// provider asynchrone
		AsyncDataProvider<BottleProxy> dataProdiver = new AsyncDataProvider<BottleProxy>() {
			@Override
			protected void onRangeChanged(HasData<BottleProxy> display) {
				// final Range range = display.getVisibleRange();
				final int start = display.getVisibleRange().getStart();
				final int displayLength = display.getVisibleRange().getLength();
				Request<List<BottleProxy>> getReq = getBottles(searchbox
						.getValue());
				lastDataBottleReceiver = new Receiver<List<BottleProxy>>() {
					@Override
					public void onSuccess(List<BottleProxy> response) {
						int end = (start + displayLength) >= response.size() ? response
								.size() : (start + response.size());
						cellTable.setVisibleRange(start, end);
						updateRowCount(response.size(), true);
						updateRowData(start, response);
						lastBottlesData = new ArrayList<BottleProxy>(response);
					}

					@Override
					public void onFailure(ServerFailure error) {
						GWT.log("---6>" + error.getMessage());
					}

				};
				getReq.fire(lastDataBottleReceiver);
			}
		};
		dataProdiver.addDataDisplay(cellTable);
	}

	/**
	 * Mise a jour du tableau
	 * 
	 * @param event
	 */
	@UiHandler("updateButton")
	void onUpdatebuttonClick(ClickEvent event) {
		populateTable();
	}

	/**
	 * Provider des cles primaires des bouteilles presentes dans le tableau
	 */
	private static final ProvidesKey<BottleProxy> KEY_PROVIDER = new ProvidesKey<BottleProxy>() {
		public Object getKey(BottleProxy item) {
			return item.getId();
		}
	};

	/**
	 * Cree le tableau principal
	 */
	private void createTable() {
		/*
		 * Ce tableau gere la selection via un checkbox selection model Un CB
		 * est necessaire pour la suppression
		 */
		final SelectionModel<BottleProxy> checkboxSelectionModel = new MultiSelectionModel<BottleProxy>(
				KEY_PROVIDER);

		cellTable.setSelectionModel(checkboxSelectionModel,
				DefaultSelectionEventManager
						.<BottleProxy> createCheckboxManager());

		/**
		 * definitions des colonnes
		 * 
		 * */
		Column<BottleProxy, Boolean> checkColumn = new Column<BottleProxy, Boolean>(
				new CheckboxCell(true, false)) {
			@Override
			public Boolean getValue(BottleProxy object) {
				return checkboxSelectionModel.isSelected(object);
			}
		};
		cellTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant(""));
		// cellTable.setColumnWidth(checkColumn, 40, Unit.PX);

		final Receiver<Void> updateReceiver = new Receiver<Void>() {
			@Override
			public void onSuccess(Void response) {
				// rien
			}

			@Override
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
				Window.alert("La modification a echouee");
			}

			@Override
			public void onViolation(Set<Violation> errors) {
				Window.alert("La modification a echouee : Parametres incorrects");
			}
		};

		// NOM
		final EditTextCell nameCell = new EditTextCell();
		Column<BottleProxy, String> nameColumn = new Column<BottleProxy, String>(
				nameCell) {
			@Override
			public String getValue(BottleProxy object) {
				return object.getName();
			}

		};
		// nameColumn.setSortable(true);
		nameColumn.setFieldUpdater(new FieldUpdater<BottleProxy, String>() {
			@Override
			public void update(int index, BottleProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				BottleRequest request = bottlerequestFactory.bottleRequest();
				BottleProxy proxy = request.edit(object);
				proxy.setName(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});
		nameColumn.setSortable(true);
		cellTable.addColumn(nameColumn, "Nom");

		// nom de la bouteille
		final EditTextCell denominationCell = new EditTextCell();
		Column<BottleProxy, String> denominationColumn = new Column<BottleProxy, String>(
				denominationCell) {
			@Override
			public String getValue(BottleProxy object) {
				return object.getDenomination() == null ? "" : object
						.getDenomination();
			}

		};
		// appellation
		denominationColumn
				.setFieldUpdater(new FieldUpdater<BottleProxy, String>() {
					@Override
					public void update(int index, BottleProxy object,
							String value) {
						// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

						BottleRequest request = bottlerequestFactory
								.bottleRequest();
						BottleProxy proxy = request.edit(object);
						proxy.setDenomination(value);
						request.update().using(proxy).fire(updateReceiver);
						return;
					}
				});
		denominationColumn.setSortable(true);
		cellTable.addColumn(denominationColumn, "Appellation");

		// producteur
		final EditTextCell producerCell = new EditTextCell();
		Column<BottleProxy, String> producerColumn = new Column<BottleProxy, String>(
				producerCell) {
			@Override
			public String getValue(BottleProxy object) {
				return object.getProducerLabel();
			}

		};
		// nameColumn.setSortable(true);
		producerColumn.setFieldUpdater(new FieldUpdater<BottleProxy, String>() {
			@Override
			public void update(int index, BottleProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				if (!"".equals(value)) {
					BottleRequest request = bottlerequestFactory
							.bottleRequest();
					BottleProxy proxy = request.edit(object);
					proxy.setProducerID(Long.valueOf(value));
					request.update().using(proxy).fire(updateReceiver);
				}
				return;
			}
		});
		producerColumn.setSortable(true);
		cellTable.addColumn(producerColumn, "Producteur");

		// nameColumn.setSortable(true);

		// quantite
		final SelectionCell quantityCell = new SelectionCell(NotesFactory
				.getFactory().getNotes());
		Column<BottleProxy, String> quantityColumn = new Column<BottleProxy, String>(
				quantityCell) {
			@Override
			public String getValue(BottleProxy object) {
				return object.getQuantity().toString();
			}

		};

		quantityColumn.setFieldUpdater(new FieldUpdater<BottleProxy, String>() {
			@Override
			public void update(int index, BottleProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));
				try {
					BottleRequest request = bottlerequestFactory
							.bottleRequest();
					BottleProxy proxy = request.edit(object);
					proxy.setQuantity(Long.valueOf(value));
					request.update().using(proxy).fire(updateReceiver);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return;
			}
		});
		cellTable.addColumn(quantityColumn, "Quantit�");
		DateTimeFormat dateFormat = DateTimeFormat
				.getFormat(PredefinedFormat.DATE_SHORT);
		// producteur
		final DatePickerCell acquiredCell = new DatePickerCell(dateFormat);

		Column<BottleProxy, Date> acquiredColumn = new Column<BottleProxy, Date>(
				acquiredCell) {
			@Override
			public Date getValue(BottleProxy object) {
				return object.getAcquired();
			}

		};
		// date d acquisition
		acquiredColumn.setFieldUpdater(new FieldUpdater<BottleProxy, Date>() {
			@Override
			public void update(int index, BottleProxy object, Date value) {
				BottleRequest request = bottlerequestFactory.bottleRequest();
				BottleProxy proxy = request.edit(object);
				proxy.setAcquired(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});
		acquiredColumn.setSortable(true);
		cellTable.addColumn(acquiredColumn, "Achet� le ");

		// A boire
		final DatePickerCell todrinkCell = new DatePickerCell(dateFormat);
		Column<BottleProxy, Date> todrinkColumn = new Column<BottleProxy, Date>(
				todrinkCell) {
			@Override
			public Date getValue(BottleProxy object) {
				return object.getToDrink();
			}

		};
		todrinkColumn.setFieldUpdater(new FieldUpdater<BottleProxy, Date>() {
			@Override
			public void update(int index, BottleProxy object, Date value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				BottleRequest request = bottlerequestFactory.bottleRequest();
				BottleProxy proxy = request.edit(object);

				proxy.setToDrink(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});
		todrinkColumn.setSortable(true);
		cellTable.addColumn(todrinkColumn, "A boire le ");

		// ajout d un lien clickable pour la degustation

		ClickableTextCell tastingclickCell = new ClickableTextCell();
		Column<BottleProxy, String> tastingclickcolumn = new Column<BottleProxy, String>(
				tastingclickCell) {
			@Override
			public String getValue(BottleProxy object) {
				return "Evaluer " + object.getName();
			}
		};

		tastingclickcolumn
				.setFieldUpdater(new FieldUpdater<BottleProxy, String>() {
					@Override
					public void update(int index, BottleProxy object,
							String value) {

						TastingUI dialogBox = new TastingUI(object);
						dialogBox.setVisible(true);
						dialogBox.center();
						dialogBox.show();
					}
				});
		cellTable.addColumn(tastingclickcolumn, "Evaluer");
		pager.setDisplay(cellTable);
		pager.setPageSize(PAGE_SIZE);
	}

	/**
	 * Supprime la ligne selectionnee du tableau
	 * 
	 * @param event
	 */
	@UiHandler("deleteButton")
	void onDeleteButtonClick(ClickEvent event) {
		deleteSelectedItems();
	}

	/**
	 * @TODO factoriser
	 */
	private void deleteSelectedItems() {
		if (lastDataBottleReceiver != null) {
			BottleRequest req = bottlerequestFactory.bottleRequest();
			for (BottleProxy current : lastBottlesData)
				if (cellTable.getSelectionModel().isSelected(current)) {
					BottleProxy toremove = req.edit(current);
					req.remove().using(toremove);
				}
			req.fire(new Receiver<Void>() {
				@Override
				public void onSuccess(Void response) {
                                        Window.alert("Suppression Réussie");
					populateTable();
				}
			});
		}
	}

	@UiField
	Button updateButton;

	@UiField
	Button updateButton1;

	@UiField
	Button deleteButton;

	@UiField
	Button deleteButton1;

	/**
	 * MAJ le tableau
	 * 
	 * @param event
	 */
	@UiHandler("updateButton1")
	void onUpdatebutton1Click(ClickEvent event) {
		populateTable();
		// cellTable.redraw();
	}

	/**
	 * Supprime
	 * 
	 * @param event
	 */
	@UiHandler("deleteButton1")
	void onDeleteButton1Click(ClickEvent event) {
		deleteSelectedItems();
	}

	/*
	 * Styles
	 */
	interface SelectionStyle extends CssResource {
		String selectedRow();
	}

	interface TableResources extends CellTable.Resources {
		@Source({ CellTable.Style.DEFAULT_CSS, "BottlesListCellTable.css" })
		TableStyle cellTableStyle();
	}

	/**
	 * The styles applied to the table.
	 */
	interface TableStyle extends CellTable.Style {
	}

	@UiFactory
	CellTable<ProducerProxy> createCellTable() {
		CellTable.Resources resources = GWT.create(TableResources.class);
		return new CellTable<ProducerProxy>(20, resources);
	}

	@UiHandler("searchbutton")
	void onSearchbuttonClick(ClickEvent event) {
		final String criteria = searchbox.getValue();
		populateTable();
	}

	@UiField
	Button searchbutton;

	@UiField
	SuggestBox searchbox;

	MultiWordSuggestOracle suggestOracle;

	Receiver<List<BottleProxy>> suggestboxreceiver;

	@UiFactory
	SuggestBox createSearchbox() {
		suggestOracle = new MultiWordSuggestOracle();
		SuggestBox box = new SuggestBox(suggestOracle);
		box.getTextBox().addKeyUpHandler(new KeyUpHandler() {

			@Override
			public void onKeyUp(KeyUpEvent arg0) {

				final String criteria = searchbox.getValue();
				if (criteria.length() > 2) {
					BottleRequest request = bottlerequestFactory
							.bottleRequest();
					Request<List<BottleProxy>> getReq = request
							.findBottlesByCriteria(criteria);
					suggestboxreceiver = new Receiver<List<BottleProxy>>() {
						@Override
						public void onSuccess(List<BottleProxy> response) {
							for (BottleProxy current : response) {
								suggestOracle.add(current.getName());
							}
							searchbox.showSuggestionList();
						}

						@Override
						public void onFailure(ServerFailure error) {
							super.onFailure(error);
							Window.alert("Une erreur est surveune :-(");
						}
					};
					getReq.fire(suggestboxreceiver);
				}
			}
		});
		return box;
	}
}
